查看原文
其他

vmware自定义规范定制虚拟机-python

木讷大叔爱运维 木讷大叔爱运维 2022-07-13



之前介绍过了vcenter自定义规范定制虚拟机-vsphere client,在图形化界面实现了虚拟机定制,虽然在一定程度上简化了操作,但是我觉得最终的应用场景应该是接入我们内部的自动化平台,打通cmdb、跳板机、监控等组件,因此我们来继续介绍下python模块pyvmomi实现虚拟机定制,希望能给大家带来一定的启发。

环境准备

名称
版本
备注
vCenter
5.5.0-218311
vCenter Server5.5 Update 2b
Centos
7.5
模板自带IP:192.168.3.253
pyvmomi
6.7.3

python
2.7.15

pyvmomi模块提供了一些实例,我们以clone_vm.py例子进行了整合修改。

虚拟机订制流程

pyvmomi实现自定义规范定制和vsphere client不同,它的流程如下:

1.通过clone_vm函数从模板克隆虚拟机,注意克隆完成后不要启动;

2.克隆完成后,在关机状态下通过ip_assign函数按照自定义规范进行定制;

3.自定义完成后,虚拟机是关闭的,需要通过powerOn函数启动;

实现

1.网络配置

def ip_assign(vm, vm_ip, vm_name): """设置IP地址""" adaptermap = vim.vm.customization.AdapterMapping() adaptermap.adapter = vim.vm.customization.IPSettings() adaptermap.adapter.ip = vim.vm.customization.FixedIp() adaptermap.adapter.ip.ipAddress = vm_ip adaptermap.adapter.subnetMask = "255.255.255.0" adaptermap.adapter.gateway = "192.168.3.1" #adaptermap.adapter.dnsDomain = "localhost" """dns设置""" globalip = vim.vm.customization.GlobalIPSettings() globalip.dnsServerList = "114.114.114.114" """设置主机名""" ident = vim.vm.customization.LinuxPrep() #ident.domain = "localhost" ident.hostName = vim.vm.customization.FixedName() ident.hostName.name = vm_name customspec = vim.vm.customization.Specification() customspec.nicSettingMap = [adaptermap] customspec.globalIPSettings = globalip customspec.identity = ident print "Reconfiguring VM Networks . . ." task = vm.Customize(spec=customspec) wait_for_task(task)

以上主要实现IP地址设置、dns设置、主机名设置,由于我们在模板中对CPU、MEMORY、DISK等已经定义完毕,基于模板进行定制,因此没有此方面的定义。

2.虚拟机启动

默认自定义完成后,虚拟机是关机状态的,我们需要开机操作才能和其他流程整合。

#根据虚拟机名获取objvm = get_obj(content, [vim.VirtualMachine], args.vm_name)#执行开机操作task = vm.PowerOn()wait_for_task(task)

3.clone_vm_customize.py实现

clone_vm.py 是只对虚拟机模板的克隆,不具有自定义规范的功能,因此我们通过对其进行网络配置、虚拟机启动进行整合,才能实现真正的自定义克隆模板的定制。

基于clone_vm.py整合如下:

vim clone_vm_customize.py#!/usr/bin/env python#-*- coding: utf-8 -*-"""Written by Dann BohnGithub: https://github.com/whereismyjetpackEmail: dannbohn@gmail.com
Clone a VM from template example"""
from pyVmomi import vimfrom pyVim.connect import SmartConnect, SmartConnectNoSSL, Disconnectimport atexitimport argparseimport getpass
from add_nic_to_vm import add_nic

def get_args(): """ Get arguments from CLI """ parser = argparse.ArgumentParser( description='Arguments for talking to vCenter')
parser.add_argument('-s', '--host', required=True, action='store', help='vSpehre service to connect to')
parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on')
parser.add_argument('-u', '--user', required=True, action='store', help='Username to use')
parser.add_argument('-p', '--password', required=False, action='store', help='Password to use')
parser.add_argument('-v', '--vm-name', required=True, action='store', help='Name of the VM you wish to make')
parser.add_argument('--no-ssl', action='store_true', help='Skip SSL verification')
parser.add_argument('--template', required=True, action='store', help='Name of the template/VM \ you are cloning from')
parser.add_argument('--datacenter-name', required=False, action='store', default=None, help='Name of the Datacenter you\ wish to use. If omitted, the first\ datacenter will be used.')
parser.add_argument('--vm-folder', required=False, action='store', default=None, help='Name of the VMFolder you wish\ the VM to be dumped in. If left blank\ The datacenter VM folder will be used')
parser.add_argument('--datastore-name', required=False, action='store', default=None, help='Datastore you wish the VM to end up on\ If left blank, VM will be put on the same \ datastore as the template')
parser.add_argument('--datastorecluster-name', required=False, action='store', default=None, help='Datastorecluster (DRS Storagepod) you wish the VM to end up on \ Will override the datastore-name parameter.')
parser.add_argument('--cluster-name', required=False, action='store', default=None, help='Name of the cluster you wish the VM to\ end up on. If left blank the first cluster found\ will be used')
parser.add_argument('--resource-pool', required=False, action='store', default=None, help='Resource Pool to use. If left blank the first\ resource pool found will be used')
parser.add_argument('--power-on', dest='power_on', action='store_true', help='power on the VM after creation')
parser.add_argument('--opaque-network', required=False, help='Name of the opaque network to add to the VM')
args = parser.parse_args()
if not args.password: args.password = getpass.getpass( prompt='Enter password')
return args
def wait_for_task(task): """ wait for a vCenter task to finish """ task_done = False while not task_done: if task.info.state == 'success': return task.info.result
if task.info.state == 'error': print("there was an error") task_done = True

def get_obj(content, vimtype, name): """ Return an object by name, if name is None the first found object is returned """ obj = None container = content.viewManager.CreateContainerView( content.rootFolder, vimtype, True) for c in container.view: if name: if c.name == name: obj = c break else: obj = c break
return obj

def ip_assign(vm, vm_ip, vm_name): """自定义规范设置""" """设置IP地址""" adaptermap = vim.vm.customization.AdapterMapping() adaptermap.adapter = vim.vm.customization.IPSettings() adaptermap.adapter.ip = vim.vm.customization.FixedIp() adaptermap.adapter.ip.ipAddress = vm_ip adaptermap.adapter.subnetMask = "255.255.255.0" adaptermap.adapter.gateway = "192.168.3.1" #adaptermap.adapter.dnsDomain = "localhost" """dns设置""" globalip = vim.vm.customization.GlobalIPSettings() globalip.dnsServerList = "114.114.114.114" """设置主机名""" ident = vim.vm.customization.LinuxPrep() #ident.domain = "localhost" ident.hostName = vim.vm.customization.FixedName() ident.hostName.name = vm_name customspec = vim.vm.customization.Specification() customspec.nicSettingMap = [adaptermap] customspec.globalIPSettings = globalip customspec.identity = ident print "Reconfiguring VM Networks . . ." #task = get_obj([vim.VirtualMachine],vm).Customize(spec=customspec) task = vm.Customize(spec=customspec) wait_for_task(task)
def clone_vm( content, template, vm_name, si, datacenter_name, vm_folder, datastore_name, cluster_name, resource_pool, power_on, datastorecluster_name): """ Clone a VM from a template/VM, datacenter_name, vm_folder, datastore_name cluster_name, resource_pool, and power_on are all optional. """
# if none git the first one datacenter = get_obj(content, [vim.Datacenter], datacenter_name)
if vm_folder: destfolder = get_obj(content, [vim.Folder], vm_folder) else: destfolder = datacenter.vmFolder
if datastore_name: datastore = get_obj(content, [vim.Datastore], datastore_name) else: datastore = get_obj( content, [vim.Datastore], template.datastore[0].info.name)
# if None, get the first one cluster = get_obj(content, [vim.ClusterComputeResource], cluster_name)
if resource_pool: resource_pool = get_obj(content, [vim.ResourcePool], resource_pool) else: resource_pool = cluster.resourcePool
vmconf = vim.vm.ConfigSpec()
if datastorecluster_name: podsel = vim.storageDrs.PodSelectionSpec() pod = get_obj(content, [vim.StoragePod], datastorecluster_name) podsel.storagePod = pod
storagespec = vim.storageDrs.StoragePlacementSpec() storagespec.podSelectionSpec = podsel storagespec.type = 'create' storagespec.folder = destfolder storagespec.resourcePool = resource_pool storagespec.configSpec = vmconf
try: rec = content.storageResourceManager.RecommendDatastores( storageSpec=storagespec) rec_action = rec.recommendations[0].action[0] real_datastore_name = rec_action.destination.name except: real_datastore_name = template.datastore[0].info.name
datastore = get_obj(content, [vim.Datastore], real_datastore_name)
# set relospec relospec = vim.vm.RelocateSpec() relospec.datastore = datastore relospec.pool = resource_pool
clonespec = vim.vm.CloneSpec() clonespec.location = relospec clonespec.powerOn = power_on
print("cloning VM...") task = template.Clone(folder=destfolder, name=vm_name, spec=clonespec) wait_for_task(task)

def main(): """ Let this thing fly """ args = get_args()
# connect this thing si = None if args.no_ssl: si = SmartConnectNoSSL( host=args.host, user=args.user, pwd=args.password, port=args.port) else: si = SmartConnect( host=args.host, user=args.user, pwd=args.password, port=args.port) # disconnect this thing atexit.register(Disconnect, si)
content = si.RetrieveContent() template = None
template = get_obj(content, [vim.VirtualMachine], args.template)
if template: #克隆模板 clone_vm( content, template, args.vm_name, si, args.datacenter_name, args.vm_folder, args.datastore_name, args.cluster_name, args.resource_pool, args.power_on, args.datastorecluster_name) vm = get_obj(content, [vim.VirtualMachine], args.vm_name) if args.opaque_network: add_nic(si, vm, args.opaque_network) #自定义规范定制虚拟机 ip_assign(vm, "192.168.3.254", args.vm_name) else: print("template not found") #启动虚拟机 vm = get_obj(content, [vim.VirtualMachine], args.vm_name) task = vm.PowerOn() wait_for_task(task)
# start this thingif __name__ == "__main__": main()
```

4.执行命令

#-s: vcenter地址#-u: vcenter账户#-p: vcneter密码#-v: 虚拟机和主机名we123#--template: 克隆的模板名称template_centos7#--datacenter-name: 数据中心unicom-idc#--vm-folder:新建虚拟机所在的文件夹test#--datastore-name: 虚拟机挂载的存储vm.datastore1#--cluster-name: 虚拟机所在集群idcpython clone_vm_customize.py -s 192.168.3.xxx -u vcenter@vsphere.local -p xxxxxxx -v we123 --template template_centos7 --datacenter-name unicom-idc --vm-folder test --datastore-name vm.datastore1 --cluster-name idc  --no-ssl

执行完成后,根据ip_assign(vm, "192.168.3.254", args.vm_name)实现虚拟机的网络定制如下:

ip地址:192.168.3.254;

子网掩码:255.255.255.0;

网关:192.168.3.1;

DNS:114.114.114.114;

虚拟机名和主机名:we123;

总结

经过实验对比,此次的虚拟机定制过程可以在不到3分钟的时间内交付一台虚拟机,大大的提高了运维的工作效率。至于交付的虚拟机剩余工作,我们需要结合自己的实际情况与其他组件进行对接。




关注我们









您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存